﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Diagnostics;
using System.Reflection;
using Zcu.PanelComposer.Interfaces;

namespace Zcu.PanelComposer.Models.Repository
{
    /// <summary>
    /// Implementace zakladnich operaci nad DB a tabulkami.
    /// </summary>
    public abstract class BaseRepository : IRepository, IDisposable
    {
        #region Fields

        private Stopwatch _watch;

        #endregion // Fields

        #region Properties

        public abstract DataContext Service { get; set; }

        #if DEBUG
        public Stopwatch Watch
        {
            get
            {
                if (_watch == null)
                {
                    _watch = new Stopwatch();
                }
                return _watch;
            }
        }
        #endif

        #endregion // Properties

        #region CRUD methods

        /// <summary>
        /// Pridani entity do tabulky.
        /// </summary>
        /// <typeparam name="T">typ tabulky</typeparam>
        /// <param name="entity">entita</param>
        public void Add<T>(T entity) where T : class
        {
            var table = Service.GetTable<T>();
            table.InsertOnSubmit(entity);
        }

        /// <summary>
        /// Smazani entity z tabulky.
        /// </summary>
        /// <typeparam name="T">typ tabulky</typeparam>
        /// <param name="entity">entita</param>
        public void Delete<T>(T entity) where T : class
        {
            var table = Service.GetTable<T>();
            table.DeleteOnSubmit(entity);
        }

        /// <summary>
        /// Deletes the before commit.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity">The entity.</param>
        public void DeleteBeforeCommit<T>(T entity) where T : class
        {
            var changes = Service.GetChangeSet();
            var obj = changes.Inserts.FirstOrDefault(i => i == entity);

            Service.GetTable(obj.GetType()).DeleteOnSubmit(obj);
        }

        /// <summary>
        /// Smazani všech řádků tabulky.
        /// </summary>
        /// <typeparam name="T">typ tabulky</typeparam>
        public void DeleteAll<T>() where T : class
        {
            var table = Service.GetTable<T>();
            table.DeleteAllOnSubmit<T>(Service.GetTable<T>().ToList());
        }

        /// <summary>
        /// Uprava entity v tabulce.
        /// </summary>
        /// <typeparam name="T">typ tabulky</typeparam>
        /// <param name="entity">entita</param>
        public void Update<T>(T entity) where T : class
        {
            //var table = Service.GetTable<T>();
            //table.Attach(entity);
           Service.Refresh(RefreshMode.KeepCurrentValues, entity);
        }

        /// <summary>
        /// Uprava entity v tabulce.
        /// </summary>
        /// <typeparam name="T">typ tabulky</typeparam>
        /// <param name="entity">entita</param>
        public void Update<T>(T entity, T original) where T : class
        {
            var table = Service.GetTable<T>();
            table.Attach(entity, original);
        }

        /// <summary>
        /// Commit zmen.
        /// </summary>
        public void Commit()
        {
            Service.SubmitChanges();
            //try
            //{
            //    Service.SubmitChanges();
            //}
            //catch (Exception exp)
            //{
            //    string msg = exp.Message;
            //}
        }

        /// <summary>
        /// Metoda vrati zmeny vseho.
        /// </summary>
        public void RollBackAll()
        {
            var changes = Service.GetChangeSet();

            foreach (var insertion in changes.Inserts)
            {
                Service.GetTable(insertion.GetType()).DeleteOnSubmit(insertion);
            }

            foreach (var deletion in changes.Deletes)
            {
                Service.GetTable(deletion.GetType()).InsertOnSubmit(deletion);
            }

            foreach (var updation in changes.Updates)
	        {
                Service.Refresh(RefreshMode.OverwriteCurrentValues, updation);
	        }
        }

        #endregion // Crud methods

        #region Select methods

        /// <summary>
        /// Vytazeni vsech zaznamu z tabulky.
        /// </summary>
        /// <typeparam name="T">typ zaznamu</typeparam>
        /// <returns>list vsech zaznamu</returns>
        public IList<T> GetAll<T>() where T : class
        {
            #if DEBUG
            Watch.Start();
            #endif
            IList<T> ret = Service.GetTable<T>().ToList();
            #if DEBUG
            Watch.Stop();
            Console.WriteLine("{0} - {1} : {2} ms", MethodInfo.GetCurrentMethod(), typeof(T).ToString(), Watch.ElapsedMilliseconds);
            Watch.Reset();
            #endif
            return ret;
        }

        /// <summary>
        /// Vytazeni vsech zaznamu z tabulky dle podminek.
        /// </summary>
        /// <typeparam name="T">typ zaznamu</typeparam>
        /// <param name="condition">podminky</param>
        /// <returns></returns>
        public IList<T> GetAll<T>(Func<T, bool> condition) where T : class
        {
            #if DEBUG
            Watch.Start();
            #endif
            IList<T> ret = Service.GetTable<T>().Where(condition).ToList();
            #if DEBUG
            Watch.Stop();
            Console.WriteLine("{0} - {1} : {2} ms", MethodInfo.GetCurrentMethod(), typeof(T).ToString(), Watch.ElapsedMilliseconds);
            Watch.Reset();
            #endif
            return ret;
        }

        /// <summary>
        /// Vytazeni jednoho zaznamu dle podminek.
        /// </summary>
        /// <typeparam name="T">typ zaznamu</typeparam>
        /// <param name="condition">podminky</param>
        /// <returns></returns>
        public T GetById<T>(Func<T, bool> condition) where T : class
        {
            #if DEBUG
            Watch.Start();
            #endif
            T ret = Service.GetTable<T>().Where(condition).FirstOrDefault();
            #if DEBUG
            Watch.Stop();
            Console.WriteLine("{0} - {1} : {2} ms", MethodInfo.GetCurrentMethod(), typeof(T).ToString(), Watch.ElapsedMilliseconds);
            Watch.Reset();
            #endif
            return ret;
        }

        #endregion // Select methods

        #region Disposable method

        /// <summary>
        /// Odstraneni.
        /// </summary>
        public void Dispose()
        {
            Service.Dispose();
        }

        #endregion // Disposable method
    }
}
